#ifndef FERMAT_COMMON_BUFFER_SLICE_H_
#define FERMAT_COMMON_BUFFER_SLICE_H_
#include <string>
#include <cstring>
#include <cstddef>
#include <cassert>
#include <memory>
#include <deque>

namespace fermat {

template <size_t N>
class BufferSlice {
public:
	BufferSlice()
	: _write_pos(_data), 
	  _read_pos(_data),
	  _end(_data + N)
	{

	}

	char* mutablePeek()
	{
		return _read_pos;
	}

	const char* peek() const 
	{
		return _read_pos;
	}

	char* writePos()
	{
		return _write_pos;
	}

	void retrieve(size_t n)
	{
		assert(n < size());
		_read_pos += n;
		if(_read_pos == _write_pos) {
			reset();
		}
	}

	void retrieveAll()
	{
		reset();
	}

	void writed(size_t n)
	{
		_write_pos += n;	
	}
	size_t writeAbleSize()
	{
		return _end - _write_pos;
	}

	size_t capacity()
	{
		return N;
	}

	bool empty()
	{
		return _write_pos == _read_pos;
	}

	size_t size()
	{
		return _write_pos - _read_pos;
	}

	void reset()
	{
		_read_pos = _data;
		_write_pos = _data;
	}

	bool append(const char *d, size_t len)
	{
		if(len > writeAbleSize()) {
			return false;
		}
		memcpy(_write_pos, d, len);
		_write_pos += len;
		return true;
	}

	bool append(const std::string &str) 
	{
		return append(str.data(), str.size());
	}

	void shrink()
	{
		size_t len = size();
		if(len == N) {
			return ;
		}
		if(len == 0) {
			reset();
			return;
		}

		std::copy(_read_pos, _write_pos, _data);
		_read_pos = _data;
		_write_pos = _data + len;
	}

	char *rawData()
	{
		return _data;
	}

	std::string toString()
	{
		return std::string(_read_pos, _write_pos);
	}

private:
	char        _data[N];
	char       *_write_pos;
	char       *_read_pos;
	char       *_end; 
};
typedef BufferSlice<8092> PageBufferSlice;
typedef std::shared_ptr<BufferSlice<8092> > PageBufferSlicePtr;
typedef std::deque<PageBufferSlicePtr> PageBufferSliceQueue;
typedef std::deque<PageBufferSlicePtr>::iterator PageBufferSliceQueueItr;
typedef std::shared_ptr<PageBufferSliceQueue> PageBufferSliceQueuePtr;

}
#endif